// BiblePage.cpp : implementation file
//

#include "stdafx.h"
#include "SwordBible.h"

#include "BiblePage.h"
#include ".\biblepage.h"
#include "ColorMgr.h"
#include "Search.h"
#include "BibleForm.h"


// CBiblePage dialog
int CBiblePage::staticPageCount = 0;  // number of pages created

sword::SWModule* CBiblePage::pGreek = NULL;
sword::SWModule* CBiblePage::pHebrew = NULL;
sword::SWModule* CBiblePage::pThayer = NULL;
sword::SWModule* CBiblePage::pRobinson = NULL;
CSwordBibleDoc* CBiblePage::pDoc = NULL;						// pointer to the document object
CString CBiblePage::ActiveMainFrameCommand = "";



// load the font of the page display
CSwordBibleFonts CBiblePage::font;

IMPLEMENT_DYNAMIC(CBiblePage, CPropertyPage)

CBiblePage::CBiblePage()
	: CPropertyPage(CBiblePage::IDD)
{
	staticPageCount++;				// increment the instance counter
	pModule = NULL;					// set pModule to point to NULL
	pModulePlain = NULL;
	version = "";

}

CBiblePage::~CBiblePage()
{
	staticPageCount--;  // an instance of property page is destroyed

	// save the active bible key
	AfxGetApp()->WriteProfileString("BiblePage","LastKey", (CString) CSwordBibleDoc::key );

	
}

void CBiblePage::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_BIBLEPAGE_RICHCTRL, RTFCtrl);
	DDX_Control(pDX, IDC_BIBLEPAGE_SPLITRICH, SplitRich);
}


BEGIN_MESSAGE_MAP(CBiblePage, CPropertyPage)
	ON_WM_SIZE()
	ON_COMMAND(ID_COPY, OnCopy)
	ON_COMMAND(ID_BIBLEPAGE_SELECTALL, OnSelectAll)
	ON_COMMAND(ID_BIBLEPAGE_DISPLAY, OnMainDisplayOptions)
	ON_COMMAND(ID_BIBLEPAGE_SEARCH, OnSearch)
	ON_COMMAND(ID_BIBLEPAGE_COPYVERSE,OnCopyVerse)
	ON_COMMAND(ID_NEXT,OnNextChapter)
	ON_COMMAND(ID_PREVIOUS,OnPreviousChapter)
	ON_COMMAND(ID_BIBLEPAGE_PRINT,OnPrint)
	ON_MESSAGE(ID_BIBLEPAGE_COMMAND,OnMainFrameCommand)

	ON_COMMAND(ID_ZOOM, OnZoom)
	ON_UPDATE_COMMAND_UI(ID_ZOOM, OnUpdateZoom)

	ON_COMMAND(ID_SPLITBIBLE, OnSplit)
	ON_UPDATE_COMMAND_UI(ID_SPLITBIBLE, OnUpdateSplit)


	ON_WM_CTLCOLOR()
	
   ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipNotify)
   ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipNotify)
   ON_NOTIFY(EN_MSGFILTER, IDC_BIBLEPAGE_RICHCTRL, OnEnMsgfilter)
END_MESSAGE_MAP()


// CBiblePage message handlers

BOOL CBiblePage::OnInitDialog()
{
	CPropertyPage::OnInitDialog();

		

	// set the title of the page
	CWnd * pWnd = GetDlgItem(IDC_STATIC_TITLE);
	if(pModule && pWnd)
		pWnd->SetWindowText(pModule->Description());


	//load the font and construct the RTF
	font.location = AFX_MAINBIBLE;
	font.Load();
	font.ConstructRTF();
	RTFCtrl.SetBackgroundColor(FALSE, CColorMgr::RTFtoCOLORREF(font.bg_color) );
	SplitRich.SetBackgroundColor(FALSE, CColorMgr::RTFtoCOLORREF(font.bg_color) );

	// Show the chapter in the biblepage window
	ShowChapter();

	//calculate the width and height of chars
	TEXTMETRIC tm;
	CClientDC dc(GetDlgItem(IDC_BIBLEPAGE_RICHCTRL));
	dc.GetTextMetrics(&tm);
	font.text_cx = tm.tmAveCharWidth;
	font.text_cy = tm.tmHeight + tm.tmExternalLeading;

	// Load the toolbar on the biblepage
	LoadToolbar();

	// Enable tool tips
	EnableToolTips();   // enable tool tips for view


	// to receive the mouse click events
	RTFCtrl.SetEventMask(ENM_MOUSEEVENTS | ENM_KEYEVENTS | ENM_SCROLLEVENTS);
	SplitRich.SetEventMask(ENM_MOUSEEVENTS | ENM_KEYEVENTS | ENM_SCROLLEVENTS);


	
	// change the font of the title and move it to the correct location

	CFont staticTextFont;
	staticTextFont.CreatePointFont(190,"Georgia",NULL);	
	GetDlgItem(IDC_STATIC_TITLE)->SetFont(&staticTextFont);
	MoveTitle();


	return TRUE;  // return TRUE unless you set the focus to a control
	// EXCEPTION: OCX Property Pages should return FALSE
}

void CBiblePage::OnSize(UINT nType, int cx, int cy)
{
	CPropertyPage::OnSize(nType, cx, cy);

	// resize and reposition the page title
	if(CSwordBibleDoc::showTitle)
	MoveTitle();


	// resize the rich edit  control(s)
    if(::IsWindow(RTFCtrl.GetSafeHwnd()) == FALSE) return;

	if(CSwordBibleDoc::bibleSplit == FALSE) 
	RTFCtrl.SetWindowPos(NULL,10,45,cx-20,cy-55,SWP_NOZORDER | SWP_NOACTIVATE);

	else
	{
        
		RTFCtrl.SetWindowPos(NULL,10,55,cx-20, (cy/2) - 38,SWP_NOZORDER | SWP_NOACTIVATE);
		
		
		if(::IsWindow(SplitRich.GetSafeHwnd()) == FALSE) return;
		SplitRich.SetWindowPos(NULL,10, (cy/2)+ 20 ,cx-20, (cy/2) - 30,SWP_NOZORDER | SWP_NOACTIVATE);


	}

	

}

void CBiblePage::SizeRichEdits()
{

	 RECT rc;
     GetWindowRect (&rc);
   	 ScreenToClient (&rc);
	 int cx = rc.right - rc.left;
	 int cy = rc.bottom - rc.top;

	// resize the rich edit  control(s)
    if(::IsWindow(RTFCtrl.GetSafeHwnd()) == FALSE) return;

	if(CSwordBibleDoc::bibleSplit == FALSE) 
	RTFCtrl.SetWindowPos(NULL,10,45,cx-20,cy-55,SWP_NOZORDER | SWP_NOACTIVATE);

	else
	{
        
		RTFCtrl.SetWindowPos(NULL,10,45,cx-20, (cy/2) - 38,SWP_NOZORDER | SWP_NOACTIVATE);
		
		
		if(::IsWindow(SplitRich.GetSafeHwnd()) == FALSE) return;
		SplitRich.SetWindowPos(NULL,10, (cy/2)+ 20 ,cx-20, (cy/2) - 30,SWP_NOZORDER | SWP_NOACTIVATE);


	}


}



void CBiblePage::OnCopy() 
{

	// only the active page should handle the message
  if(  !( ((CPropertySheet*) GetParent())->GetActivePage()   == this) )  
	  return;

  RTFCtrl.Copy();

 }

void CBiblePage::OnSelectAll()
{
		// only the active page should handle the message
  if(  !( ((CPropertySheet*) GetParent())->GetActivePage()   == this) )  
	  return;

  RTFCtrl.SetSel(0,-1);

}




void CBiblePage::OnMainDisplayOptions() 
{

	// only the active page should handle the message
  if(     ((CPropertySheet*) GetParent())->GetActivePage()   != this) return;

  CColorMgr colordlg(NULL, &font);

	
  if(colordlg.DoModal() == IDOK)
  	 
  {
	  RTFCtrl.SetBackgroundColor(false, CColorMgr::RTFtoCOLORREF(font.bg_color) );
	  SplitRich.SetBackgroundColor(false, CColorMgr::RTFtoCOLORREF(font.bg_color) );
	  ShowChapter();
  }
  


	
}

LONG CBiblePage::OnMainFrameCommand(UINT, LONG)
{
	 if(ActiveMainFrameCommand == "print") OnPrint();
	 else if (ActiveMainFrameCommand == "copy") OnCopy();
	 else if (ActiveMainFrameCommand == "selectall") OnSelectAll();
	 else if (ActiveMainFrameCommand == "display") OnMainDisplayOptions();
	 else if (ActiveMainFrameCommand == "zoom") OnZoom();
	// else if (ActiveMainFrameCommand == "zoomupdate") OnUpdateZoom();
	 else if (ActiveMainFrameCommand == "search") OnSearch();
	 else if (ActiveMainFrameCommand == "split") OnSplit();
	 else if (ActiveMainFrameCommand == "previous") OnPreviousChapter();
	 else if (ActiveMainFrameCommand == "next") OnNextChapter();

		
		return 0L;
}

void CBiblePage::OnSearch() 
{

	// only the active page should handle the message
  if(     ((CPropertySheet*) GetParent())->GetActivePage()   == this)
  {
  
	  CSearch dlg(this);

	  dlg.pModule = pModulePlain;
	  dlg.font = font;
	  dlg.DoModal();
  
  }
	

}

	

void CBiblePage::OnCopyVerse() 
{  
		// only the active page should handle the message
  if(  !( ((CPropertySheet*) GetParent())->GetActivePage()   == this) )  
	  return;

  pModule->SetKey(CSwordBibleDoc::key);
  CString strData = *pModule;

	// TODO: Add your command handler code here
	if (OpenClipboard())
  {
   // Empty the Clipboard. This also has the effect
   // of allowing Windows to free the memory associated
   // with any data that is in the Clipboard
   EmptyClipboard();

   // Ok. We have the Clipboard locked and it's empty. 
   // Now let's allocate the global memory for our data.

   // Here I'm simply using the GlobalAlloc function to 
   // allocate a block of data equal to the text in the
   // "to clipboard" edit control plus one character for the
   // terminating null character required when sending
   // ANSI text to the Clipboard.
   HGLOBAL hClipboardData;
   hClipboardData = GlobalAlloc(GMEM_DDESHARE, 
                                strData.GetLength()+1);

   // Calling GlobalLock returns to me a pointer to the 
   // data associated with the handle returned from 
   // GlobalAlloc
   char * pchData;
   pchData = (char*)GlobalLock(hClipboardData);
		  
   // At this point, all I need to do is use the standard 
   // C/C++ strcpy function to copy the data from the local 
   // variable to the global memory.
   strcpy(pchData, LPCSTR(strData));
		  
   // Once done, I unlock the memory - remember you 
   // don't call GlobalFree because Windows will free the 
   // memory automatically when EmptyClipboard is next 
   // called. 
   GlobalUnlock(hClipboardData);
		  
   // Now, set the Clipboard data by specifying that 
   // ANSI text is being used and passing the handle to
   // the global memory.
   SetClipboardData(CF_TEXT,hClipboardData);
		  
   // Finally, when finished I simply close the Clipboard
   // which has the effect of unlocking it so that other
   // applications can examine or modify its contents.
   CloseClipboard();
  }


}



// this function loads the toolbar on the bible page
int CBiblePage::LoadToolbar(void)
{
	
  if (!m_wndFormatBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD
       | WS_VISIBLE | CBRS_TOP |  CBRS_FLYBY | CBRS_TOOLTIPS) ||
       !m_wndFormatBar.LoadToolBar(IDR_TOOLBAR_BIBLE))
   {
      TRACE0("Failed to create toolbar\n");
      return -1;      // fail to create
   }

   // buttons size: 16
   // bitmaps:
   // enabled - IDB_TOOLBAR_NORMAL
   // hovered - IDB_TOOLBAR_HOT
   // disabled - IDB_TOOLBAR_DISABLED
   // transparent color RGB(255, 0, 255)
   m_wndFormatBar.LoadTCToolBar(24, IDB_TOOLBAR_BIBLE,IDB_TOOLBAR_BIBLE,
                              IDB_TOOLBAR_BIBLE, RGB(255,255,255));




	// Position the control bars using RepositionBars. 
	RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0);

	// Expand the size of the Toolbar window so all controls in it would fit
	
	CRect toolBarRect;
	CToolBarCtrl& formatBar = m_wndFormatBar.GetToolBarCtrl();
	formatBar.GetWindowRect(toolBarRect);
	ScreenToClient(toolBarRect);
	toolBarRect.left += 10  ;
	toolBarRect.right += 500  ;
	formatBar.MoveWindow(toolBarRect,TRUE);



	

	return 0;
}


// display the relevant chapter text in the bible page window
void CBiblePage::ShowChapter(void)
{
	CString start;
	sword::VerseKey key = CSwordBibleDoc::key;
	

	if (!pModule) return;   // check that pointer is not NULL


		// clear limits
	   	MorphLimits.Clear();
		StrongLimits.Clear();
		Footnotes.RemoveAll();
		Xrefs.RemoveAll();
		XLimits.Clear();
	
		
		// get the chapter
		int chap = (CSwordBibleDoc::key).Chapter();
	

		// Get the book
		CString book = key.getBookAbbrev();
		int b = key.Book();
		start.Format("%s %d:1", book ,chap);
		
		chapText = font.GetHeaderRTF();
		
		CStringArray VA; // verse array
	
		// get the text line by line
		for (key = start ; !key.Error() && key.Chapter() == chap && b ==  key.Book(); key++){

			VA.Add(key.getShortText());

			pModule->SetKey(key);         // set key to current verse
			CString renderText = (CString) pModule->RenderText();  //need to resolve the key before calling AddHeadings
			

			if(CSwordBibleDoc::heading_tags) AddHeadings(chapText);
			
			// the verse use the color cf1 in the color table
			chapText = chapText +  "\\cf1\\b "+ key.getShortText() + " \\b0 ";

			// the text uses the color cf2 in the color table
			chapText += "\\cf2 ";

			renderText.Replace("\\par"," ");
			renderText.Replace("\\cf6","\\cf9");

			chapText += renderText;
			if(CSwordBibleDoc::fn_tags) AddFootNotes(renderText, key.Verse());
			if(CSwordBibleDoc::crossref_tags) AddXref(renderText, key.Verse());
	
			chapText += "\\par ";	// each verse on a separate line
				
		}

		// Append the footnotes
		int count = Footnotes.GetCount();

		if(count)
		{
		chapText += "\\par\\cf5\\\ul Footnotes:\\ul0\\par\\sub ";	
		for(int i = 0; i < count ; i++) chapText = chapText +  pModule->RenderText(Footnotes.GetAt(i)) + "\\par ";
		}

        
	chapText += "}"; 

	// footnote tags are enclosed between href tags in bibles. Footnotes use color cf5 in the color table 
	// x reference tags are enclosed between href tags in bibles. cross references use color cf6 in the color table 
	chapText.Replace("<a href=\"\">*n",  "\\cf5\\b *n");
	chapText.Replace("<a href=\"\">*x",  "\\cf6\\b *x");
	chapText.Replace("</a>", "\\cf2\\b0 ");
	chapText.Replace("<a href=\"\">",  " ");
	 
	RTFCtrl.SetRTF(chapText);
	

	ZoomText();


	SetVerseLimits(VA);
	if(CSwordBibleDoc::morph_tags && version == "KJV")   SetMorphLimits();
	if(CSwordBibleDoc::lemma_tags && version == "KJV")   SetStrongLimits();
	if(CSwordBibleDoc::crossref_tags) SetXLimits();


	
			
}
// Sets the upper and lower char position bounds of all the verses displayed in the RichEditCtrl
void CBiblePage::SetVerseLimits(CStringArray& va)
{
	VerseLimits.Clear(); // clear any limits from previously displayed chapter

	FINDTEXTEX ft1;      // FINDTEXTEX structure that would be used for searching for keys(verse abbr.) in rich control
	ft1.chrg.cpMin = 0;
	ft1.chrg.cpMax = -1;

	const int count = va.GetCount();   // this is the total number of verses
	int begin[200];                    // array large enough to hold the beginning position of all verses
	for(int i = 0; i < count; i++)
	{
	ft1.lpstrText =  va.GetAt(i);                      // the key (abbreviation for the verse e.g. Gen 1:1)
	int foundAt = RTFCtrl.FindText(FR_DOWN , &ft1); 	// position of the first character of the verse abbr.
	if(foundAt != -1) {	  begin[i] = foundAt;   ft1.chrg.cpMin = foundAt;	} // store the position in integer array

	}

	// store the upper and lower limits of all the verses
	for(int j = 0; j < count - 1; j++)
		VerseLimits.Add(begin[j], begin[j+1] - 1, va.GetAt(j));
	    VerseLimits.Add(begin[count - 1], RTFCtrl.GetTextLength(), va.GetAt(count-1) );
}



// Fills the StrongLimits structure with upper and lower position bounds of strong numbers in the RichEditCtrl
void CBiblePage::SetStrongLimits()
{
	
	FINDTEXTEX ft1, ft2;
	ft1.chrg.cpMin = 0;
	ft1.chrg.cpMax = -1;
	ft1.lpstrText = "<";

	ft2.chrg.cpMin = 0;
	ft2.chrg.cpMax = -1;
	ft2.lpstrText = ">";

	int start = 0, end = 0;


	while (true) {
	
	start = RTFCtrl.FindText(FR_DOWN , &ft1); //find the href start tags  
	end = RTFCtrl.FindText(FR_DOWN , &ft2); //find the href tags  

	if(start == -1 || end == -1 || start > end) return;

	CString ref = "";
	RTFCtrl.GetTextRange(start + 1, end, ref);
	StrongLimits.Add(start, end, ref);
	

	ft1.chrg.cpMin = start + 1;
	ft2.chrg.cpMin = end + 1;

	}
}

void CBiblePage::SetXLimits()
{
	int count = Xrefs.GetCount();
	FINDTEXTEX ft1;
	ft1.chrg.cpMin = 0;
	ft1.chrg.cpMax = -1;
	int pos;
	CString left, right;
	int start, end;


	for(int i =0; i < count; i++)
	{
		CString str = Xrefs.GetAt(i);
		pos = str.Find("$$$");
		left = str.Left(pos);
		right = str.Mid(pos + 3);

		ft1.lpstrText = left;

		start = RTFCtrl.FindText(FR_DOWN , &ft1);
		end = start + left.GetLength() - 1;

		XLimits.Add(start, end, right);

		ft1.chrg.cpMin = start + 1;

	}
}



// Fills the MorphLimits structure with upper and lower position bounds of morph numbers in the RichEditCtrl
void CBiblePage::SetMorphLimits()
{
	FINDTEXTEX ft1, ft2;
	ft1.chrg.cpMin = 0;
	ft1.chrg.cpMax = -1;
	ft1.lpstrText = "(";

	ft2.chrg.cpMin = 0;
	ft2.chrg.cpMax = -1;
	ft2.lpstrText = ")";

	int start = 0, end = 0;


	while (true) {
	
	start = RTFCtrl.FindText(FR_DOWN , &ft1); //find the href start tags  
	end = RTFCtrl.FindText(FR_DOWN , &ft2); //find the href tags  

	if(start == -1 || end == -1 || start > end) return;

	CString ref = "";
	RTFCtrl.GetTextRange(start + 1, end, ref);
	MorphLimits.Add(start, end, ref);
	

	ft1.chrg.cpMin = start + 1;
	ft2.chrg.cpMin = end + 1;

	}
	
}

void CBiblePage::AddXref(CString& VerseText, int verse)
{
	
	int found  = 0;
	int index  = 1;

	CString findtext;
	CString verseStr;
	CString indexStr;
	CStringArray x_label;


	

	verseStr.Format("%d", verse);

	for(index = 1; index < 15; index++)
	{
	indexStr.Format("%d", index);
	findtext = "*x" + verseStr + "." + indexStr;

	found = VerseText.Find(findtext);

	if(found != -1) x_label.Add(findtext);		
	}


	int c = 0;
	int count = x_label.GetCount();
	sword::AttributeList &xrefl = pModule->getEntryAttributes()["Footnote"]; 

	for (sword::AttributeList::iterator& it = xrefl.begin(); it != xrefl.end() && c < count; it++) 
	{
		CString xtext= it->second["refList"];
		if(xtext.GetLength() >= 2)	Xrefs.Add( x_label.GetAt(c++) + "$$$" + xtext );
	}
								
	
					
}




void CBiblePage::OnReset()
{
	// TODO: Add your specialized code here and/or call the base class
ShowChapter();

	//CPropertyPage::OnReset();
}

BOOL CBiblePage::OnSetActive()
{
	
	  ShowChapter();
	 
    // show or hide the bottom window
	if(CSwordBibleDoc::bibleSplit) 
	{
		SplitRich.ShowWindow(SW_SHOW);
		SplitRich.SetRTF( RTFCtrl.GetRTF() );

		if(CSwordBibleDoc::bibleZoom) SplitRich.SendMessage(EM_SETZOOM, 5,4); //zoom by 1.25

	}

	 SizeRichEdits();

	
	return CPropertyPage::OnSetActive();
}

// moves the static text box on the bible page.
// moves the background image of the title 
// This static box contains the title of the book and chapter being displayed
void CBiblePage::MoveTitle(void)
{
	CRect rect;
	this->GetWindowRect(&rect);
	ScreenToClient(&rect);
	CWnd * pWnd = GetDlgItem(IDC_STATIC_TITLE);


	if(! ::IsWindow(pWnd ->GetSafeHwnd() ))  return;  // check if window is there
	
	pWnd ->SetWindowPos( NULL, 630, 5 , 250 , 100 ,
		SWP_NOZORDER | SWP_NOACTIVATE);

	}

HBRUSH CBiblePage::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
	HBRUSH hbr = CPropertyPage::OnCtlColor(pDC, pWnd, nCtlColor);

	// TODO:  Change any attributes of the DC here
		if (pWnd->GetDlgCtrlID() == IDC_STATIC_TITLE)		
		{		pDC->SetTextColor(0x800000);
				//pDC->SetBkColor(0xCCFFCC);
				
				
		}

		

	// TODO:  Return a different brush if the default is not desired
	return hbr;
}








void CBiblePage::OnNextChapter()
{

	int chap = CSwordBibleDoc::Chapter();

	CSwordBibleDoc::key.Chapter(chap + 1);

	pDoc->UpdateAllViews(NULL,0,0);

	
}


void CBiblePage::OnPreviousChapter()
{
	int chap = CSwordBibleDoc::key.Chapter();

	CSwordBibleDoc::key.Chapter(chap - 1);

	pDoc->UpdateAllViews(NULL,0,0);


}



void CBiblePage::OnPrint()
{
		// only the active page should handle the message
		if(  !( ((CPropertySheet*) GetParent())->GetActivePage()   == this) )  
	  return;

	CBibleForm::pControl = (CRichEditCtrl *) GetDlgItem(IDC_BIBLEPAGE_RICHCTRL);
		AfxGetMainWnd()->SendMessageToDescendants(WM_PRINT_CONTROL, (WPARAM) 1 , 0);


	   
}




BOOL CBiblePage::OnToolTipNotify(UINT id, NMHDR *pNMHDR,   LRESULT *pResult)
{
   // need to handle both ANSI and UNICODE versions of the message
   TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
   TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
   CString strTipText;
   UINT nID = pNMHDR->idFrom;
   if (pNMHDR->code == TTN_NEEDTEXTA && (pTTTA->uFlags & TTF_IDISHWND) ||
      pNMHDR->code == TTN_NEEDTEXTW && (pTTTW->uFlags & TTF_IDISHWND))
   {
      // idFrom is actually the HWND of the tool
      nID = ::GetDlgCtrlID((HWND)nID);
   }

   char buf[100];

   if (nID != 0) // will be zero on a separator
   {AfxLoadString(nID,buf,100 ); strTipText.Format("%s",buf);  }

   if (pNMHDR->code == TTN_NEEDTEXTA)
      lstrcpyn(pTTTA->szText, strTipText, sizeof(pTTTA->szText));
   else
      _mbstowcsz(pTTTW->szText, strTipText, sizeof(pTTTW->szText));
   *pResult = 0;

   return TRUE;    // message was handled
}





void CBiblePage::AddFootNotes(CString& VerseText, int verse)
{
	
	int found  = 0;
	int index  = 1;

	CString findtext;
	CString verseStr;
	CString indexStr;
	CStringArray fn_label;
	CString fntext;



	verseStr.Format("%d", verse);

	for(index = 1; index < 15; index++)
	{
	indexStr.Format("%d", index);
	findtext = "*n" + verseStr + "." + indexStr;

	found = VerseText.Find(findtext);

	if(found != -1) fn_label.Add(findtext);
		
	}


	int c = 0;
	int count = fn_label.GetCount();
	
	sword::AttributeList &fnl = pModule->getEntryAttributes()["Footnote"]; 

	for (sword::AttributeList::iterator& it = fnl.begin(); it != fnl.end() && c < count; it++) 
	{
		fntext= it->second["body"];
		if(fntext.GetLength() > 1 && it->second["type"] != "crossReference" )	Footnotes.Add( fn_label.GetAt(c++) + " " + fntext );
	}


	
										
						
}

// add pre-verse headings to the beginning of each verse
void CBiblePage::AddHeadings(CString& Text)
{
		int pvHeading = 0;
		char buf[10];
		BOOL heading = TRUE;
		sword::SWKey * key = pModule->getKey();
		
		
		while(heading == TRUE){
		sprintf(buf, "%i", pvHeading++);
		sword::SWBuf pvh = pModule->getEntryAttributes()["Heading"]["Preverse"][buf].c_str(); 

		CString preverseHeading =  pModule->RenderText(pvh);
			

		if(preverseHeading.GetLength() < 2) heading = FALSE;
		else Text = Text + "\\par\\cf2\\b\\i " + preverseHeading + "\\i0\\b0\\par\\par ";
		}

	     pModule->SetKey(key);
		pModule->RenderText();


}



void CBiblePage::OnEnMsgfilter(NMHDR *pNMHDR, LRESULT *pResult)
{
	MSGFILTER *pMsgFilter = reinterpret_cast<MSGFILTER *>(pNMHDR);
	// TODO:  The control will not send this notification unless you override the
	// CPropertyPage::OnInitDialog() function to send the EM_SETEVENTMASK message
	// to the control with either the ENM_KEYEVENTS or ENM_MOUSEEVENTS flag 
	// ORed into the lParam mask.

	if(pMsgFilter->msg == WM_MOUSEMOVE )
	{
		 CPoint point;                                            
         ::GetCursorPos(&point); //where is the mouse?

		 // change the coordinates of the point from Screen to that of richedit
		  RTFCtrl.ScreenToClient(&point);

		 int nchar =  RTFCtrl.CharFromPos(point);
		 int line = RTFCtrl.LineFromChar(nchar);

		 CString number = "";
		 CString dlgTitle = "";
		 int lower = 0, upper = 0;
		 
		 if(StrongLimits.FromPos(nchar, lower, upper, number) || MorphLimits.FromPos(nchar, lower, upper, number)
			 || XLimits.FromPos(nchar, lower, upper, number) ) 
		 SetCursor(CBibleSheet::m_hHandCursor);
	}



	if(pMsgFilter->msg == WM_LBUTTONDOWN )
	{ 
		CPoint point;                                            
        ::GetCursorPos(&point); //where is the mouse?

		// change the coordinates of the point from Screen to that of richedit
		RTFCtrl.ScreenToClient(&point);

		int nchar =  RTFCtrl.CharFromPos(point);

		CString number = "";
		CString keylist = "";
		CString tip = "";
		CString dlgTitle = "";
		CString curVerse;
		int lower, upper;
		p = NULL;

		if( VerseLimits.FromPos(nchar,lower,upper,curVerse) == TRUE) 
		{

		CString prev_key  = (CSwordBibleDoc::key).getShortText();

		 if(curVerse != "" && prev_key != curVerse) 
		 {
         
		 	FINDTEXTEX ft1;
			ft1.chrg.cpMin = 0;
			ft1.chrg.cpMax = -1;
		
			ft1.lpstrText = prev_key;
			int ps = RTFCtrl.FindText(FR_DOWN,&ft1);
			int pe = prev_key.GetLength();

			if(ps == -1) return;

			RTFCtrl.SetSel(ps, ps + pe);
			RTFCtrl.SetSelColor( CColorMgr::RTFtoCOLORREF(font.verse_color));


			ft1.lpstrText = curVerse;

			int s = RTFCtrl.FindText(FR_DOWN,&ft1);
			if(s == -1) return;

			int e = curVerse.GetLength();
				 
			RTFCtrl.SetSel(s, s + e);
			RTFCtrl.SetSelColor(RGB(139,26,26));
			
			CSwordBibleDoc::key = curVerse;
			}
		}





		 if(StrongLimits.FromPos(nchar, lower, upper, number))
		 {
			 if(CSwordBibleDoc::key.Testament() == 1) // old testament
				 p = pHebrew;
			 else if(CSwordBibleDoc::key.Testament() == 2) // new testament
				 p = pGreek;
			
			 dlgTitle = "Strong's Tags";
			 
		}

		else if(MorphLimits.FromPos(nchar, lower, upper, number))
		 {
			 if(CSwordBibleDoc::key.Testament() == 1) // old testament
				 p = pThayer;
			 else if(CSwordBibleDoc::key.Testament() == 2) // new testament
				 p = pRobinson;

			 dlgTitle = "Morphological Tags";

		}

		 else if(XLimits.FromPos(nchar, lower, upper, number))
		 {
			 p = CSwordBibleDoc::pXrefModuleActive;
			 dlgTitle =  "Scripture Cross-reference";

		}

		
		 if(p == NULL) return;  // nothing to display

		
		 if (p != CSwordBibleDoc::pXrefModuleActive)
		 {
		 p->SetKey(sword::SWKey (number) );
		 if(p->Error()) return;
		
         CString fs;
	     fs.Format("\\fs%d ",22);
         tip = font.GetHeaderRTF() + fs + "\\f2\\cf7\\b " +
			 number + " \\b0\\cf8 "  + p->RenderText() + "}"; 	
		 }


		 else if(p == CSwordBibleDoc::pXrefModuleActive)

		 {

		CString keylist = number;
		
		//keylist.Replace(',',';');

		 // parse the verse list
	    sword::VerseKey vk;
	    sword::ListKey list = vk.ParseVerseList(keylist, vk , TRUE);
	
		
    // this string contains the RTF for the tooltip that would be displayed
	tip = font.GetHeaderRTF();

	sword::VerseKey key = "";

	CString fs;
	fs.Format("\\fs%d ",22);
	tip += fs;
			
	// iterate through the list of verses and get the corresponsing text for each verse
	for(list= sword::TOP; !list.Error(); list++)
   {
	   
	 key = (const char*) list;

	 p->SetKey(key);

	 tip += "\\f2\\cf7\\b " + (CString) p->KeyText() + "\\b0\\cf8 " 
		 + " " + p->RenderText()  + "\\par\\par";
	  
	}

   tip += "}";

	}
		 

   // if l1 and l2 are different, then the link has been split into two lines
         int l1 = RTFCtrl.LineFromChar(lower);
		 int l2 = RTFCtrl.LineFromChar(upper);
    		
		 int x1 = RTFCtrl.PosFromChar(lower).x;
		 int x2 = RTFCtrl.PosFromChar(upper).x + font.text_cx;
		 int y1 = RTFCtrl.PosFromChar(lower).y;
		 int y2 = y1 + font.text_cy;

		 // the mouse is over the portion of the link that is in line 1
		 if(l1 != l2 && point.y <= y2) 
		 {
			 CRect r;
			 RTFCtrl.GetWindowRect(&r);
			 RTFCtrl.ScreenToClient(&r);
			 x2 = r.right;
		 }

		  // the mouse is over the portion of the link that is in line 2
		 else if(l1 != l2 && point.y > y2)
		 {
			 x1 = 0;
			 y1 = RTFCtrl.PosFromChar(upper).y;
			 y2 = y1 + font.text_cy;
		 }

	
		 CRect rect(x1,y1, x2, y2);

	
		 CBibleSheet::DisplayReference(tip, dlgTitle);


	
	}



    else if (pMsgFilter->msg == WM_RBUTTONDOWN)   OnRightButtonDown();
   
  
               
 

	
*pResult = 0; 



}

void CBiblePage::OnRightButtonDown()
{

	  CPoint point;                                            
     ::GetCursorPos(&point); //where is the mouse?
     CMenu menu; //lets display out context menu :) 
     DWORD dwSelectionMade;                                       
     VERIFY(menu.LoadMenu(IDR_MENU_BIBLEPAGE) );  
     CMenu *pmenuPopup = menu.GetSubMenu(0);
     ASSERT(pmenuPopup != NULL);   

	  if(CSwordBibleDoc::bibleZoom)	pmenuPopup->CheckMenuItem(ID_BIBLE_ZOOMTEXT,MF_CHECKED); 
	  if(CSwordBibleDoc::bibleSplit)	pmenuPopup->CheckMenuItem(ID_BIBLE_SPLITVIEW,MF_CHECKED); 

     dwSelectionMade = pmenuPopup->TrackPopupMenu( (TPM_LEFTALIGN|TPM_LEFTBUTTON|
                                                      TPM_RETURNCMD),
                                                    point.x, point.y, this); 

	

	
	switch (dwSelectionMade)
	{
	case ID_BIBLE_PRINT:		   OnPrint(); break;
	case ID_BIBLE_COPY:			   OnCopy(); break;
	case ID_BIBLE_SELECTALL:       OnSelectAll(); break;
	case ID_BIBLE_DISPLAY:		   OnMainDisplayOptions(); break;    
	case ID_BIBLE_ZOOMTEXT:        OnZoom(); break; 
	case ID_BIBLE_SPLITVIEW:       OnSplit(); break;
	case ID_BIBLE_SEARCH:          OnSearch(); break;
	case ID_BIBLE_PREVIOUSCHAPTER: OnPreviousChapter(); break;
	case ID_BIBLE_NEXTCHAPTER:     OnNextChapter(); break;

	}

	
	pmenuPopup->DestroyMenu(); 



}


void CBiblePage::OnZoom()
{
	// only the active page should handle the message
		if(  !( ((CPropertySheet*) GetParent())->GetActivePage()   == this) )  
	  return;


	CSwordBibleDoc::bibleZoom = !(CSwordBibleDoc::bibleZoom);

	ZoomText();

}

void CBiblePage::OnUpdateZoom(CCmdUI *pCmdUI)
{
	pCmdUI->SetCheck(CSwordBibleDoc::bibleZoom);
	
}

void CBiblePage::ZoomText()
{
	if(CSwordBibleDoc::bibleZoom) RTFCtrl.SendMessage(EM_SETZOOM, 5,4); //zoom by 1.25
	else RTFCtrl.SendMessage(EM_SETZOOM, 0,0);  // turn off zooming

	if(CSwordBibleDoc::bibleSplit == FALSE) return;

	if(CSwordBibleDoc::bibleZoom) SplitRich.SendMessage(EM_SETZOOM, 5,4); //zoom by 1.25
	else SplitRich.SendMessage(EM_SETZOOM, 0,0);  // turn off zooming
}

void CBiblePage::OnSplit()
{

	// only the active page should handle the message
		if(  !( ((CPropertySheet*) GetParent())->GetActivePage()   == this) )  
	  return;


	CSwordBibleDoc::bibleSplit = !(CSwordBibleDoc::bibleSplit);
    
	// show or hide the bottom window
	if(CSwordBibleDoc::bibleSplit) 
	{
		SplitRich.ShowWindow(SW_SHOW);
		SplitRich.SetRTF( RTFCtrl.GetRTF() );

		if(CSwordBibleDoc::bibleZoom) SplitRich.SendMessage(EM_SETZOOM, 5,4); //zoom by 1.25
	
	}
	else SplitRich.ShowWindow(SW_HIDE);

	

	SizeRichEdits();

	

}

void CBiblePage::OnUpdateSplit(CCmdUI *pCmdUI)
{
	pCmdUI->SetCheck(CSwordBibleDoc::bibleSplit);
	
}